<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <!-- 注意: 先引入 react基础库,再引入react dom解析库 -->
  <script src="lib/react/react.development.js"></script>
  <script src="lib/react/react-dom.development.js"></script>
  <script src="lib/babel.min.js"></script>
  <style>
    *{
      margin: 0;
      padding: 0;
    }
    .ul-chat{
      width: 200px;
      height: 200px;
      border: 1px solid red;
      margin: 30px;
      overflow: auto;
    }
    .ul-chat>li{
      height: 30px;
      font-size: 20px;
      line-height: 30px;
      text-indent: 2em;
    }

  </style>
</head>
<body>
  <!-- 完整的声明周期函数 -->
  <div id="root"></div>
  <script type="text/babel">
    class HelloWorld extends React.Component {
      constructor(props){
        super(props);
        console.log('constructor....');
        // 创建ref
        this.chatUlRef = React.createRef();
        this.state = {
          chatItems: [
            {
              id: 1,
              text: '吃了么'
            },
            {
              id: 2,
              text: '吃了!'
            },
            {
              id: 3,
              text: '吃啥了?'
            },
            {
              id: 4,
              text: '吃好吃的!'
            }
          ]
        }
        // bind
        this.handleKeyUp = this.handleKeyUp.bind(this);
      }
      
      componentDidMount(){
        
      }
      // 在state被更新后触发,而又没来得及更新到UI的时候
      // 这里可以获取到更新之前的UI状态,比如滚轮位置
      // prevState 上一次的state
      // 此生命周期方法的任何返回值将作为参数传递给 componentDidUpdate()。
      getSnapshotBeforeUpdate(prevProps, prevState){
        // 1. 得到之前容器的高度
        // 注意: 必须是等内容高度发生变化的时候再处理
        if(this.state.chatItems.length > prevState.chatItems.length){
          // 这里没来得及更新UI,所以得到的是上一次更新后的DOM
          var chatUl = this.chatUlRef.current;
          // 之前的容器内容高度
          var preContentHeight = chatUl.scrollHeight - chatUl.scrollTop;
          return preContentHeight;
        }
        // 如果聊天列表高度没变化,则返回null
        return null;
        
      }
      // snapshot 是通过getSnapshotBeforeUpdate声明周期函数返回的
      componentDidUpdate(prevProps, prevState, snapshot){
        console.log('didUpdate....',this.state);
        console.log('snapshot',snapshot);
        // 2. 用更新后的最新高度 - 原来的内容高度 得到的就是需要被卷进去的高度
        if(snapshot){
          var chatUl = this.chatUlRef.current;
          // 计算需要被卷入的高度(多余的高度)
          var useScrollTop = chatUl.scrollHeight - snapshot;
          // 3. 赋值
          chatUl.scrollTop = useScrollTop;
        }
        
      }
      // 如果是输入了enter,需要把最新文本内容 更新到state.chatItems
      handleKeyUp(e){
        // keyCode 可以获取键盘按键的 Ascii编码值
        var keyCode = e.keyCode;
        // 如果值== 13 说明是enter键
        if(keyCode == 13){
          // 获取input的value
          // 不能直接修改state的值,必须通过setState才能触发render()!!!
          // 所以如果state的某个值是对象类型,需要先克隆
          // [...xxx] 数组结构
          var chatItems = [...this.state.chatItems];
          chatItems.push({
            id: new Date().getTime(), // 时间戳肯定不同
            text: e.target.value
          })
          // 用setState更新
          this.setState({
            chatItems
          })
          // 更新后还原输入框
          e.target.value = '';
        }
      }
      render(){
        console.log('render....',this.state);
        var liItems = this.state.chatItems.map(item=>(
          <li key={item.id}>{item.text}</li>
        ))
        return (
          <div>
              <input type="text" onKeyUp={this.handleKeyUp} placeholder="请输入聊天内容" />
              <ul className="ul-chat" ref={this.chatUlRef}>
                  {liItems}
              </ul>
          </div>
        )
      }
    }
    // 使用react 相关api 渲染到容器
    ReactDOM.render(<HelloWorld />,document.getElementById('root'));
  </script>
</body>
</html>